package com.my.socket.aio.v4;

import com.google.common.base.Throwables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * User: Alex Zhong
 * Date: 2016/6/17
 */
public class Server {
    private static final Logger LOGGER = LoggerFactory.getLogger(Server.class);

    public static void main(String[] args) throws Exception {
        int nThreads = Runtime.getRuntime().availableProcessors();
        AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withFixedThreadPool(nThreads, new ThreadFactory() {

            private AtomicInteger index = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "asynchronous-task-" + index.incrementAndGet());
            }
        });

        AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 9999);
        asynchronousServerSocketChannel.bind(inetSocketAddress);
        LOGGER.info("listen at {}", inetSocketAddress);

        while (true) {
            Future<AsynchronousSocketChannel> future = asynchronousServerSocketChannel.accept();
            AsynchronousSocketChannel asynchronousSocketChannel = future.get();
            LOGGER.info("incoming socket: {}", asynchronousSocketChannel);

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            asynchronousSocketChannel.read(byteBuffer, null, new CompletionHandler<Integer, Object>() {
                @Override
                public void completed(Integer result, Object attachment) {
                    String request = new String(byteBuffer.array(), 0, result);
                    LOGGER.info("read: {}", request);

                    String response = request.toUpperCase();
                    asynchronousSocketChannel.write(ByteBuffer.wrap(response.getBytes()), attachment, new CompletionHandler<Integer, Object>() {
                        @Override
                        public void completed(Integer result, Object attachment) {
                            LOGGER.info("write: {}", response);
                            try {
                                asynchronousSocketChannel.close();
                            } catch (IOException e) {
                                LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(e));
                            }
                        }

                        @Override
                        public void failed(Throwable exc, Object attachment) {
                            LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(exc));
                        }
                    });
                }

                @Override
                public void failed(Throwable exc, Object attachment) {
                    LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(exc));
                }
            });
        }
    }
}
